﻿using System;
using weka.core;
using weka.classifiers;
using weka.classifiers.bayes;
using System.Collections.Generic;
using Folder = OMC.DataManagement.Folder;
using MailContent = OMC.DataManagement.MailContent;
using MenuItem = OMC.DataManagement.ResultItem;

namespace OMC.Classification
{
    /// <summary>
    /// This class could manage all the things
    /// which are responsable of classification.
    /// </summary>
    public class ClassificationHandler
    {
        private Instances rawData;
        private DataLoader dataLoader { get; set; }
        private DataWriter dataWriter { get; set; }
        private bool isSetUp;
        private bool isTrained;
        private Classifier classifier;
        private TextClassifier textClassifier { get; set; }
        private Prediction prediction { get; set; }
        private double[] result;

        /// <summary>
        /// The constructor to create an object.
        /// </summary>
        public ClassificationHandler()
        {
            isSetUp = false;
            isTrained = false;
            Utils.Debug.Log("Initialized Classification handler");
        }

        /// <summary>
        /// This method could select the classifier.
        /// </summary>
        /// <param name="classifierIndex">indexOfClassifier to take</param>
        public void SetClassifier(int classifierIndex)
        {
            switch (classifierIndex)
            {
                case 0:
                    classifier = new NaiveBayesMultinomialUpdateable();
                    break;
                case 1:
                    classifier = new NaiveBayesMultinomial();
                    break;
                case 2:
                    classifier = new ComplementNaiveBayes();
                    break;
                case 3:
                    classifier = new DMNBtext();
                    break;
                default:
                    classifier = new NaiveBayesMultinomialUpdateable();
                    break;
            }
            this.Clear();
        }

        /// <summary>
        /// This method set the number of the shown folder in the
        /// context menu.
        /// </summary>
        /// <param name="count">The number of the shown folder.</param>
        public void SetCountOfShownFolderInContextMenu(int count)
        {
            Prediction.SetCountOfShownFolderInContextMenu(count);
        }

        /// <summary>
        /// This method clears all of the data, which are saved.
        /// </summary>
        public void Clear()
        {
            rawData = null;
            isSetUp = false;
            isTrained = false;
            textClassifier = new TextClassifier(classifier);
        }

        /// <summary>
        /// This method can classify a MailContent.
        /// </summary>
        /// <param name="mailToClassify">a MailContent to classify</param>
        /// <param name="folderList">a referenced list of the folders</param>
        /// <returns>a list of predicted menu items</returns>
        public List<MenuItem> Classify(MailContent mailToClassify, List<Folder> folderList)
        {
            if (isTrained)
            {
                //Classify Data
                String stringToClassyfy = mailToClassify.GetContent();
                result = textClassifier.ClassifyMessage(stringToClassyfy);

                //Evaluate the Data
                prediction = new Prediction(textClassifier, result);

                //ThePredictedClassName = ThePrediction.getPredictedClassName();
                return prediction.GetPredictedButtonList(folderList);
            }
            return null;
        }

        /// <summary>
        /// This method trains the classifier with the Train Dataset.
        /// </summary>
        public void TrainClassifier()
        {
            if (isSetUp)
            {
                textClassifier = new TextClassifier(classifier);
                textClassifier.SetTrainingSet(rawData);
                textClassifier.BuildAfterTrainingDataSet();
                isTrained = true;
            }
        }

        /// <summary>
        /// This method creates Instances of the List, which contains the Folders and
        /// MailContents of the Email Accounts.
        /// </summary>
        /// <param name="folderList">the referenced list of Folder</param>
        public void CreateInstances(List<Folder> folderList)
        {
            isSetUp = false;
            foreach (Folder folder in folderList)
            {
                textClassifier.AddClassName(folder.FolderInfo);
            }
            textClassifier.BuildAfterClassesAdded();
            foreach (Folder folder in folderList)
            {
                foreach (MailContent mailContent in folder)
                {
                    textClassifier.AddMailData(mailContent.GetContent(), folder.FolderInfo);
                }
            }
            rawData = textClassifier.GetInstancesAfterMailsAdded();
            isSetUp = true;
        }

        /// <summary>
        /// This method writes a dataset to ARFF file.
        /// </summary>
        /// <param name="filePath">the destination path inkl file name</param>
        /// <param name="isEnabled">
        /// if true, the arff file is filtered with the StringToWord filter
        /// if false, the arff file isn't filtered, it's possible to read the content of it
        /// </param>
        public void WriteInstance(String filePath, bool isEnabled)
        {
            if (isSetUp)
            {
                dataWriter = new DataWriter(rawData, filePath);
                dataWriter.DataOutput = isEnabled;
                dataWriter.Make();
            }
        }

        /// <summary>
        /// This method loads Instances from a file.
        /// </summary>
        public void LoadInstance(String filePath)
        {
            isSetUp = false;
            dataLoader = new DataLoader(filePath);
            rawData = dataLoader.Load();
            isSetUp = true;
        }

        /// <summary>
        /// This method makes a eval of the classifier.
        /// </summary>
        /// <returns>This returns the goodness in percent.</returns>
        public int GetGoodness()
        {
            if (isSetUp)
            {
                Evaluator classifierTester = new Evaluator(rawData, classifier);
                return classifierTester.getGoodness();
            }
            return -1;
        }

        /// <summary>
        /// This method could use to get the full information about
        /// the weka eval of the classifier test.
        /// </summary>
        /// <returns>This returns a string of the full test information of weka tools.</returns>
        public string GetGoodnessExtra()
        {
            return Evaluator.GetGoodnessExtra();
        }
    }
}